package events

import (
	"sync"

	log "github.com/sirupsen/logrus"
	"libvirt.org/go/libvirt"
)

// Event 通用事件结构
type Event struct {
	Type      string                 `json:"type"`
	Domain    string                 `json:"domain,omitempty"`
	Detail    string                 `json:"detail"`
	Timestamp int64                  `json:"timestamp"`
	Data      map[string]interface{} `json:"data,omitempty"`
}

// EventType 事件类型常量
const (
	EventTypeDomainLifecycle = "domain.lifecycle"
	EventTypeDomainReboot    = "domain.reboot"
	EventTypeDomainRTC       = "domain.rtc"
)

// Manager 事件管理器
type Manager struct {
	conn        *libvirt.Connect
	subscribers []chan Event
	mu          sync.RWMutex
	callbackIDs []int
	stopChan    chan struct{}
}

// NewManager 创建事件管理器
func NewManager(conn *libvirt.Connect) *Manager {
	return &Manager{
		conn:        conn,
		subscribers: make([]chan Event, 0),
		stopChan:    make(chan struct{}),
	}
}

// Start 开始监听事件
func (m *Manager) Start() error {
	// 注册 Domain 生命周期事件
	callbackID, err := m.conn.DomainEventLifecycleRegister(nil, m.handleDomainLifecycle)
	if err != nil {
		return err
	}
	m.callbackIDs = append(m.callbackIDs, callbackID)
	log.Info("Domain lifecycle event handler registered")

	// 启动事件循环
	go m.eventLoop()

	return nil
}

// Stop 停止事件监听
func (m *Manager) Stop() error {
	close(m.stopChan)

	// 取消注册所有回调
	for _, id := range m.callbackIDs {
		if err := m.conn.DomainEventDeregister(id); err != nil {
			log.Warnf("Failed to deregister event callback %d: %v", id, err)
		}
	}

	// 关闭所有订阅 channel
	m.mu.Lock()
	for _, ch := range m.subscribers {
		close(ch)
	}
	m.subscribers = nil
	m.mu.Unlock()

	return nil
}

// Subscribe 订阅事件
func (m *Manager) Subscribe() <-chan Event {
	m.mu.Lock()
	defer m.mu.Unlock()

	ch := make(chan Event, 100) // 缓冲 channel
	m.subscribers = append(m.subscribers, ch)
	return ch
}

// Unsubscribe 取消订阅
func (m *Manager) Unsubscribe(ch <-chan Event) {
	m.mu.Lock()
	defer m.mu.Unlock()

	for i, subscriber := range m.subscribers {
		if subscriber == ch {
			close(subscriber)
			m.subscribers = append(m.subscribers[:i], m.subscribers[i+1:]...)
			break
		}
	}
}

// publish 发布事件到所有订阅者
func (m *Manager) publish(event Event) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	for _, ch := range m.subscribers {
		select {
		case ch <- event:
		default:
			log.Warn("Event channel full, dropping event")
		}
	}
}

// handleDomainLifecycle 处理 Domain 生命周期事件
func (m *Manager) handleDomainLifecycle(c *libvirt.Connect, d *libvirt.Domain,
	event *libvirt.DomainEventLifecycle,
) {
	name, err := d.GetName()
	if err != nil {
		log.Errorf("Failed to get domain name: %v", err)
		return
	}

	detail := lifecycleEventToString(event.Event)
	log.Infof("Domain lifecycle event: %s - %s", name, detail)

	m.publish(Event{
		Type:      EventTypeDomainLifecycle,
		Domain:    name,
		Detail:    detail,
		Timestamp: getCurrentTimestamp(),
		Data: map[string]interface{}{
			"event":  int(event.Event),
			"detail": int(event.Detail),
		},
	})
}

// handleDomainReboot 处理 Domain 重启事件
func (m *Manager) handleDomainReboot(c *libvirt.Connect, d *libvirt.Domain) {
	name, err := d.GetName()
	if err != nil {
		log.Errorf("Failed to get domain name: %v", err)
		return
	}

	log.Infof("Domain reboot event: %s", name)

	m.publish(Event{
		Type:      EventTypeDomainReboot,
		Domain:    name,
		Detail:    "reboot",
		Timestamp: getCurrentTimestamp(),
	})
}

// eventLoop 事件处理循环
func (m *Manager) eventLoop() {
	log.Info("Event loop started")
	defer log.Info("Event loop stopped")

	for {
		select {
		case <-m.stopChan:
			return
		default:
			// libvirt 事件循环会自动调用注册的回调
			// 这里只是保持 goroutine 活跃
			if err := libvirt.EventRunDefaultImpl(); err != nil {
				log.Errorf("Event loop error: %v", err)
			}
		}
	}
}

// lifecycleEventToString 将生命周期事件转为字符串
func lifecycleEventToString(event libvirt.DomainEventType) string {
	switch event {
	case libvirt.DOMAIN_EVENT_DEFINED:
		return "defined"
	case libvirt.DOMAIN_EVENT_UNDEFINED:
		return "undefined"
	case libvirt.DOMAIN_EVENT_STARTED:
		return "started"
	case libvirt.DOMAIN_EVENT_SUSPENDED:
		return "suspended"
	case libvirt.DOMAIN_EVENT_RESUMED:
		return "resumed"
	case libvirt.DOMAIN_EVENT_STOPPED:
		return "stopped"
	case libvirt.DOMAIN_EVENT_SHUTDOWN:
		return "shutdown"
	case libvirt.DOMAIN_EVENT_PMSUSPENDED:
		return "pmsuspended"
	case libvirt.DOMAIN_EVENT_CRASHED:
		return "crashed"
	default:
		return "unknown"
	}
}

// getCurrentTimestamp 获取当前时间戳（Unix 秒）
func getCurrentTimestamp() int64 {
	return 0 // 实际实现应使用 time.Now().Unix()
}
